package com.pluto.securitydemo.config;

import com.alibaba.fastjson2.JSON;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

import java.util.HashMap;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration // 标识为配置类
@EnableMethodSecurity
public class WebSecurityConfig {

    /**
     * 这个 Bean 是 SpringSecurity 的默认 Bean(即:如果不配置,默认存在这个Bean)
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 开启授权保护
        http.authorizeRequests(authorize -> authorize.anyRequest().authenticated());

        // 这里改用自定义的登录页
        // permitAll 无需授权即可访问，防止重定向到 login 重新进入调用链导致递归。
        http.formLogin(form -> form.loginPage("/login").permitAll()
                // 默认针对的前端参数是固定的 username,password,通过下面内容进行定制处理
                .usernameParameter("username")
                .passwordParameter("password")
                // 如果验证失败，指定跳转到的地址，下面为默认值
                .failureForwardUrl("/login?error")
                // 将登录成功的处理器注册进来
                .successHandler(new MyAuthenticationSuccessHandler())
                .failureHandler(new MyAuthenticationFailureHandler())
        );
        // 注销成功处理
        http.logout(logout -> logout.logoutSuccessHandler(new MyAuthenticationLogoutSuccessHandler()));
        // 请求未认证处理
        http.exceptionHandling(exception -> {
            exception.authenticationEntryPoint(new MyAuthenticationEntryPointHandler());
            exception.accessDeniedHandler(((request, response, accessDeniedException) -> {
                HashMap<String, Object> result = new HashMap<>();
                result.put("code", -1);
                result.put("message", "没有权限");
                String json = JSON.toJSONString(result);
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().println(json);
            }));
        });

        // 关闭掉 csrf 防御：csrf 意图是，在前端页面post 请求会携带一个隐藏的 _csrf 的字符串，后台会校验一致性。
        http.csrf(csrf -> csrf.disable());

        // 开启跨域
        http.cors(withDefaults());

        // 设置只允许 1个账号登录，其他的会被超时登出
        http.sessionManagement(session -> session.maximumSessions(1).expiredSessionStrategy(new MySessionInformationExpiredStrategy()));
        return http.build();
    }

    // @Bean
    // public PasswordEncoder passwordEncoder() {
    //     return new BCryptPasswordEncoder(); // 或者使用其他PasswordEncoder实现
    // }

    // 注意 @Bean 关注的 name 是 方法名 即 byName 可以通过 @Bean.name 属性控制
    // @Bean
    // public UserDetailsService userDetailsService(){
    //     // 创建基于 内存的用户信息管理器
    //     InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
    //     // 创建 UserDetails 对象
    //     manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());
    //     return manager;
    // }

    // 注意 @Bean 关注的 name 是 方法名 即 byName 可以通过 @Bean.name 属性控制
    // @Bean
    // public UserDetailsService userDetailsService() {
    //     // 创建基于 内存的用户信息管理器
    //     return new DBUserDetailsManager();
    // }
}
